﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ParsecParser.Helpers;
using System.Collections.Concurrent;
using ParsecParser.Display;

namespace ParsecParser
{
    [Serializable]
    public class CombatDetails : CombatStatistics
    {
        public string RaidGroupName { get; set; }
        public bool DataHasBeenSynced { get; set; }
        public bool CompanionInFight { get; set; }
        public bool IsPvpFight { get; set; }
        public long CompanionDamageOut { get; set; }
        public long CompanionDamageIn { get; set; }
        public long CompanionAbsorbedIn { get; set; }
        public long CompanionHealOut { get; set; }
        public long CompanionEffectiveHealOut { get; set; }
        public long CompanionHealIn { get; set; }
        public long CompanionThreat { get; set; }
        public long HealThreat { get; set; }

        public CombatLogEvent CombatEndEvent { get; set; }
        public CombatLogEvent LastOutgoingDamage { get; set; }
        public CombatLogParticipant Companion { get; set; }
        public LogState LogStateAtStart {get;set;}

        private object EventsLock = new object();
        private object RaidDetailsLock = new object();
        private object ActivatesLock = new object();
        private Dictionary<long, ActivateDetails> ActivateList { get; set; }
        private List<CombatLogEvent> Events { get; set; }
        private List<CombatStatistics> RaidDetails { get; set; }

        public CombatDetails() : base()
        {
            LogStateAtStart = new LogState();
            EventsLock = new object();
            RaidDetailsLock = new object();
            ActivatesLock = new object();
            Events = new List<CombatLogEvent>();
            RaidDetails = new List<CombatStatistics>();
            ActivateList = new Dictionary<long, ActivateDetails>();
        }
        public ActivateDetails GetActivate(long key)
        {
            ActivateDetails a = null;
            lock (ActivatesLock)
            {
                ActivateList.TryGetValue(key, out a);
            }
            return a;
        }
        public void AddOrUpdateActivate(long key, ActivateDetails e)
        {
            if (e != null)
            {
                lock (ActivatesLock)
                {
                    ActivateList[key] = e;
                }
            }
        }
        public List<ActivateDetails> GetActivateValues()
        {
            lock (ActivatesLock)
            {
                return ActivateList.Values.ToList();
            }
        }
        public Dictionary<long, ActivateDetails> GetActivates()
        {
            lock (ActivatesLock)
            {
                return ActivateList.ToDictionary(x => x.Key, x => x.Value);
            }
        }
        public void AddEvent(CombatLogEvent e)
        {
            if (e != null)
            {
                lock (EventsLock)
                {
                    Events.Add(e);
                }
            }
        }
        public CombatLogEvent GetLastEvent()
        {
            lock (EventsLock)
            {
                return Events.LastOrDefault();
            }
        }
        public List<CombatLogEvent> GetEvents()
        {
            lock (EventsLock)
            {
                return Events.ToList();
            }
        }
        public List<CombatLogEvent> GetEvents(CombatLogFilterParameters f)
        {
            lock (EventsLock)
            {
                f = f ?? new CombatLogFilterParameters();
                return Events.ApplyFilter(f).ToList();
            }
        }
        public bool HasEvents()
        {
            if (Events == null)
                return false;
            else
            {
                lock (EventsLock)
                {
                    return Events.Count > 0;
                }
            }
        }
        public List<CombatStatistics> GetRaidDetails()
        {
            lock (RaidDetailsLock)
            {
                return RaidDetails.ToList();
            }
        }
        public void SetRaidDetails(IEnumerable<CombatStatistics> details)
        {            
            lock (RaidDetailsLock)
            {
                details = details ?? new List<CombatStatistics>();
                RaidDetails = new List<CombatStatistics>(details);
            }
        }
        public override string ToString()
        {
            StringBuilder f = new StringBuilder(StartCombat.ToString("HH:mm:ss.fff"));
            var partyList = GetParticipantList();
            if (partyList.Count > 1)
            {
                string encounterName = null;
                if (RaidEncounterDetail != null && RaidEncounterDetail.RaidEncounterId > 0 )
                {
                    encounterName = RaidEncounterDetail.ToString();
                }
                if (!string.IsNullOrEmpty(encounterName))
                {                
                    f.Append(" - ");
                    f.Append(encounterName);
                }
                else
                {
                    string[] parts = partyList.Where(y => !y.IsThisPlayer && y.DisplayName != CombatLogParticipant.EmptyParticipantName).OrderBy(y => y.IsPlayer).ThenBy(y => y.DisplayName).GroupBy(y => y.DisplayNameWithOwner).Select(y => y.Key + (y.Count() > 1 ? "(" + y.Count() + ")" : "")).Take(10).ToArray();
                    string p = string.Join(", ", parts).TruncateText(120, ", ");
                    if (IsPvpFight)
                        f.Append(" - PvP: ");
                    else
                        f.Append(" - ");
                    f.Append(p);
                }
            }
            return f.ToString();
        }
    }
}
